<?php

/**
 * 安心站长axzz.cn，一个追求技术创造者。让网站、小程序、APP牛起来……
 *
 * cighsen02 3651872575
 *
 * Create at: 2024.05.01
 * Update at: 2025.09.16
*/

namespace Twoir\Service\Member;

use Exception;
use Twoir\Service\BaseMember;
use Twoir\System\Model\EnewsMember;

use function EcmsRandInt;
use function egetipfrom;
use function egetip;
use function egetipport;
use function esetcookie;
use function eReturnMemberDefGroupid;
use function make_password;
use function md5;
use function RepPostVar;
use function substr;

/**
 * 会员登陆
*/
class Login extends BaseMember
{
    // 允许进入字段
    const ALLOW = ['username', 'password', 'email', 'phone', 'lifetime', 'key'];
    // 验证码key名称
    const LONGIN_KEY_NAME = 'checkloginkey';

    private ?string $password = null;

    public function __construct()
    {
        parent::__construct(false);

        if (!empty($this->userInfo())) throw new Exception('您已登陆，退出后重试', 7200);
    }

    /**
     * 邮箱注册
     *
     * @param array $add
     * @return array
    */
    public function email($add): array
    {
        // 参数过滤
        $add = $this->paramFilter($add);

        return [];
    }

    /**
     * 用户名注册
     *
     * @param array $add
     * @return array
     *
     * @throws Exception
    */
    public function userName(array $add): array
    {
        // 参数过滤
        $add = $this->paramFilter($add);

        $username = isset($add['username']) && $add['username'] ? trim($add['username']) : null;
        $this->password	= isset($add['password']) && $add['password'] ? trim($add['password']) : null;

        if(empty($username)) throw new Exception('用户名不能为空', 9200);

        if(empty($this->password)) throw new Exception('密码不能为空', 9200);

        $username = RepPostVar($username);
        $this->password = RepPostVar($this->password);

        return $this->handleLogin(['username' => $username], $add);
    }

    /**
     * 手机注册，在做之前请在主表增加phone字段
     *
     * @param array $add
     * @return array
    */
    public function phone($add)
    {
        // 参数过滤
        $add = $this->paramFilter($add);

        $phone = isset($add['phone']) ? trim($add['phone']) : trim($add['username']);
        $this->password	= trim($add['password']);

        if(!$phone) {

            if (!isset($add['phone'])) throw new Exception('用户名不能为空', 9200);

            throw new Exception('手机号不能为空', 9200);
        }

        if(!$this->password) throw new Exception('密码不能为空', 9200);

        $this->password	= RepPostVar($this->password);

        if(isset($add['phone']) || EnewsMember::getCount(['phone' => $phone]) > 0) {

            return $this->handleLogin(['phone' => $phone], $add);
        }

        // 手机号转为用户名登陆，即手机号为用户名
        return $this->handleLogin(['username' => RepPostVar($phone)], $add);
    }

    /**
     * 登陆处理
     * 
     * @param array $where
     * @param array $add
     * @return array
     * 
     * @throws Exception
     */
    private function handleLogin($where, $add)
    {
        global $ecms_config, $level_r, $public_r;

        // 验证码
        if($public_r['loginkey_ok']){

            if (!isset($add['key']) || empty($add['key'])) throw new Exception('验证码不能为空', 9200);

            $this->checkShowKey(static::LONGIN_KEY_NAME, $add['key'], 1);
        }

        if (empty($user = EnewsMember::getOne($where, ['userid','username','password','groupid','checked','rnd','salt','rndt','registertime'])) || !$this->doCkMemberPw($this->password, $user['password'], $user['salt'])) {

            throw new Exception('用户名不存在或密码错误', 9200);
        }

        // 默认会员组
        if(empty($user['groupid'])) $user['groupid'] = eReturnMemberDefGroupid();

        $user['groupid'] = (int)$user['groupid'];

        if(isset($level_r[$user['groupid']]['loginps']) && $level_r[$user['groupid']]['loginps'] && $level_r[$user['groupid']]['loginps'] !== $add['mg_loginps'])
        {
            throw new Exception('认证码不对', 9200);
        }

        if(0 == $user['checked']){

            if(1 == $public_r['regacttype']) throw new Exception('用户还未激活，请通过邮件激活', 9200);

            throw new Exception('用户还未审核，请耐心等待', 9200);
        }

        $rnd		= $user['rnd'];
        $rndt       = $user['rndt'];
        $eipf       = egetipfrom();
        $lastip		= egetip();
        $lastipport	= egetipport();

        $update = [
            'groupid'       => $user['groupid'],
            'lasttime'      => $this->nowtime,
            'lastip'        => $lastip,
            'loginnum'      => 'loginnum + 1',
            'lastipport'    => $lastipport,
            'isot'          => 1,
            'eipf'          => $eipf
        ];

        // 改变会员登录随机码
        if (isset($ecms_config['sets']['mpchmrnd']) && 0 === $ecms_config['sets']['mpchmrnd']) {

            $rnd    = make_password(EcmsRandInt(20,36));
            $rndt   = make_password(EcmsRandInt(20,32));
            $update += [
                'rnd' => $rnd, 
                'rndt' => $rndt
            ];
        }

        // 执行更新
        EnewsMember::update(['userid' => $user['userid']], $update);

        // 设置cookie
        $lifetime = isset($add['lifetime']) && $add['lifetime'] ? (int)$add['lifetime'] : 0;
        $logincookie = 0;
        if($lifetime) $logincookie = $this->nowtime + $lifetime;

        esetcookie('mlusername', $user['username'], $logincookie);
        esetcookie('mluserid', $user['userid'], $logincookie);
        esetcookie('mlgroupid', $user['groupid'], $logincookie);
        esetcookie('mlrnd', $rnd, $logincookie);
        esetcookie("mlrndt", $rndt, $logincookie);
        $this->qGetLoginAuthstr($user['userid'], $user['username'], $rnd, $user['groupid'], $logincookie);
        // 清空验证码
        $this->emptyShowKey(static::LONGIN_KEY_NAME);
        esetcookie('returnurl', '');

        // 移除
        unset($user['password'], $user['salt']);

        return $user;
    }

    /**
     * 验证密码
     *
     * @param string $newPassWord
     * @param string $oldPassWord
     * @param string $salt
     * @return bool
     */
    protected function doCkMemberPw(string $newPassWord, string $oldPassWord, string $salt): bool
    {
        global $ecms_config;

        if(0 == $ecms_config['member']['pwtype'])// 单重md5
        {
            if(md5($newPassWord) === $oldPassWord) return true;
        }
        elseif(1 == $ecms_config['member']['pwtype'])// 明码
        {
            if($newPassWord === $oldPassWord) return true;
        }
        elseif(3 == $ecms_config['member']['pwtype'])// 16位md5
        {
            if(substr(md5($newPassWord), 8, 16) === $oldPassWord) return true;
        }
        // 双重md5
        else{

            if(md5(md5($newPassWord) . $salt) === $oldPassWord) return true;
        }

        return false;
    }
}
